package pars;

import java.io.ObjectInputStream.GetField;
import java.util.*;

//import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter.DEFAULT;

import lex.Token;
//import ast.Expr;

import ic.ast.*;
import ic.ast.decl.*;
import ic.ast.decl.PrimitiveType.DataType;
import ic.ast.expr.*;
import ic.ast.stmt.*;
import fun.grammar.Grammar;
import fun.grammar.Word;
import fun.parser.Tree;
import fun.parser.earley.EarleyParser;
import fun.parser.earley.EarleyState;



public class LibAst {
	
	static List<DeclClass> classes=new ArrayList<DeclClass>();
	static List<DeclField> fields=new ArrayList<DeclField>();
	static List<DeclMethod> methods=new ArrayList<DeclMethod>();
	
	public static Node constructAstLib(fun.parser.Tree parseTree)   
	{

		Word r = parseTree.root;
		fun.parser.Tree[] s = 
		parseTree.subtrees.toArray(new fun.parser.Tree[0]);

		switch (r.tag) {
		
		case "S": 
			
			if(s.length==5){//class CLASS_ID { LIBMETHOD* }
				
				Token tok=(Token)s[1].root;
				constructAstLib(s[3]); //LIBMETHOD*	
				DeclClass d=new DeclClass(tok.line, tok.text, fields, methods);
				classes.add(d);
				Program pp=new Program(classes);
				return pp;
			}
			
		case "LIBMETHOD*":
			if(s.length==2){//LIBMETHOD LIBMETHOD*
				
				DeclLibraryMethod met=(DeclLibraryMethod)constructAstLib(s[0]);
				methods.add(met);
				constructAstLib(s[1]);
				return null; 
			}
			
			if(s.length==1){//epsilon
				
				return null;
			}
			
		case "LIBMETHOD": //static RETURN_VALUE ID ( FORMALSq )
			if(s.length==7){
			List<Parameter> formals=new ArrayList<Parameter>();
			
			Type type55=(Type)constructAstLib(s[1]);
			
			
			Token tok=(Token)s[2].root;
			formalStatmHelper(s[4],formals);

			return new DeclLibraryMethod(type55, tok.text , formals);
			}
			
			
		case "RETURN_VALUE": // FIELD_TYPE | void
			if(s.length==1){
			Type type19= (Type) constructAstLib(s[0]);
			return type19;
			}
			
			
		case "FIELD_TYPE":

			if(s.length==1){ //TYPE

				Type type99=(Type) constructAstLib(s[0]);
				return type99;
				
			}
			
			if(s.length==3){//FIELD_TYPE [ ]
				Type type0=(Type) constructAstLib(s[0]);
				int i;
				for(i=1;i<s.length+1;i++)	{
					if(i%2==0){
						type0.incrementDimension();
					}
				}
				
				return type0;
			}
			

			
			
		case "TYPE":
			
			if(s.length==1){
				Token t3=(Token)s[0].root;
				
				switch(s[0].root.tag){
				
				case "int":{
					
					return new PrimitiveType(t3.line,DataType.INT);
				}
				
				case "string":{
					return new PrimitiveType(t3.line,DataType.STRING);
				}
				
				case "boolean":{
					return new PrimitiveType(t3.line,DataType.BOOLEAN);
				}

				
					default:{
						
						return new ClassType(t3.line,t3.text); //to check this
					}
				}
		
				
			}
		case "void":
			
			Token t4=(Token)r;
			return new PrimitiveType(t4.line,DataType.VOID);
			
			
		case "EPSILON":

			return null;
			
		default:
			
			return null;
	
		}
	
		
		
	}
	
	public static Node formalStatmHelper(fun.parser.Tree parseTree,	List<Parameter> formals){
		
		Word r = parseTree.root;
		fun.parser.Tree[] s = 
		parseTree.subtrees.toArray(new fun.parser.Tree[0]);
		
		
		switch (r.tag){
		case "FORMALSq": 
			if(s.length==2){
				formalStatmHelper(s[0],formals); //formal
				formalStatmHelper(s[1],formals); //commaformal*
				return null;
			}
			if(s.length==1){
				return null;
			}
			
		case "FORMAL":
			Type type12=(Type) constructAstLib(s[0]);
			Token tok1=(Token) s[1].root; //the tok3.text is the id
			Parameter param=new Parameter(type12,tok1.text);
			formals.add(param);
			return null;
			
		case "COMMAFORMAL*":
			
			if(s.length==2){
				formalStatmHelper(s[0],formals); //commaformal
				formalStatmHelper(s[1],formals); //commaformal*
				return null;
			}
			
			if(s.length==1){//thats epsilon
				return null;
			}
			
		case "COMMAFORMAL":
			formalStatmHelper(s[1],formals); //commaformal*
			return null;
	}
		return null;
	

	}
}
